package com.bupt.ilink.jwt;

import com.auth0.jwt.exceptions.TokenExpiredException;
import com.bupt.ilink.utils.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;


import java.io.IOException;

public class JwtTokenAuthenticationFilter extends GenericFilterBean {

    private JwtTokenProvider jwtTokenProvider;

    private final ObjectMapper objectMapper;

    public JwtTokenAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
        this.jwtTokenProvider = jwtTokenProvider;
        this.objectMapper = new ObjectMapper();
    }

    private boolean shouldNotFilter(HttpServletRequest request) {
        String path = request.getServletPath();//TODO: jwt filter白名单需要和web security白名单保持一致
        return path.startsWith("/user/login") ||
               path.startsWith("/user/register") ||
               path.startsWith("/user/personal_register") ||
               path.startsWith("/user/refresh") ||
               path.startsWith("/user/school_login") ||
               path.startsWith("/user/publicKey");
    }

    /**
     * 将获取请求中的token解析出来，进行身份认证和鉴权
 * @param req
 * @param res
 * @param filterChain
     * @return void
     * @author liuzheng
     * @create 2024-07-27
     **/
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        if (shouldNotFilter(request)) {
            filterChain.doFilter(req, res);
            return;
        }
        try {
            String token = jwtTokenProvider.resolveToken(request);
            if (token != null) {
                jwtTokenProvider.validateToken(token);
                Authentication auth = jwtTokenProvider.getAuthentication(token);
                if (auth != null) {
                    SecurityContextHolder.getContext().setAuthentication(auth);
                }
            }
        } catch (Exception e) {
            R failure = R.failure(e.getMessage());
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType("application/json");
            response.getWriter().write(objectMapper.writeValueAsString(failure));
            response.getWriter().flush();
            return;
        }
        filterChain.doFilter(req, res);
    }

}
